/*
 *  Symtable.cpp
 *  Parser
 *
 *  Created by Christoph Ehscheidt on 10.02.08.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */

#include "Symtable.h"
#include "TokenTyp.h"

	void Symtable::addStringTabArray() {
		// Letzter Index der StringsTabs um eins erh�hens
		this->currentIndex++;

		char** newStringTabArray = new char*[this->currentIndex + 1];

		// Alte Zeiger auf StringTabArrays in neues Array �bernehmen
		for (int i = 0; i < this->currentIndex; i++) {
			newStringTabArray[i] = this->stringTabArray[i];
		}

		// Altes Array l�schen
		delete[] this->stringTabArray;

		// Neuen StringTab Array hinzuf�gen
		newStringTabArray[this->currentIndex] = new char[this->stringTabLength];
		// Zeiger auf StringTabArry aktualisieren
		this->stringTabArray = newStringTabArray;
		// Einf�gezeiger auf den Anfang des neuen StringTabArrays zeigen lassen
		this->insertPointer = this->stringTabArray[this->currentIndex];
		// Freier Platz gleich der Gr��e des neu erzeugtem StringTabArray
		this->free = this->stringTabLength;
	}

	void Symtable::initSymbols() {
		// Token + Bezeichner die zur Sprache geh�ren
		this->insert((char*) "summe",	5, TokenTyp::TOKEN_SUM);
		this->insert((char*) "produkt",	7, TokenTyp::TOKEN_PROD);
		this->insert((char*) "print",	5, TokenTyp::TOKEN_PRINT);
		this->insert((char*) "durch",	5, TokenTyp::TOKEN_DURCH);
		this->insert((char*) "modulo",	6, TokenTyp::TOKEN_MODULO);
	}

	Symtable::Symtable(int length) {
		this->charCount			= 0;
		this->currentIndex		= 0;
		this->stringTabLength	= length;
		this->free				= length;

		hashtable = new Hashtable<Element>();

		// Create Array filled with pointers to the stringTabs with size 1
		this->stringTabArray = new char*[1];
		// Initialize array with the first stringTab
		*this->stringTabArray = new char[this->stringTabLength];
		// Set insert pointer on the first position
		this->insertPointer = *this->stringTabArray;
		// index of stringTabArray
		this->currentIndex = 0;
		// Initialize reserved keywords
		initSymbols();
	}

	Symtable::~Symtable() {
		// Deletes the whole hashtable
		delete hashtable;

		// Deletes the stringTabArrays
		for (int i = 0; i <= this->currentIndex; i++) {
			delete[] stringTabArray[i];
		}

		// Deletes the array which manages the pointers to the stringTabArrays
		delete[] stringTabArray;
	}

	Element* Symtable::insert(char* lexem, int lexemLength, int tokenTyp) {
		// Einzuf�gendes Lexem darf die Gr��e des StringTab Arrays nicht �berschreiten
		assert(lexemLength + 1 <= this->stringTabLength);

		// Pr�fen ob noch Platz vorhanden ist
		if (lexemLength + 1 > free) {
			addStringTabArray();
		}

		char* lexemCpy = lexem;
		char* lexemPointer = this->insertPointer;

		while (char letter = *lexem++) {
			*insertPointer++ = letter;
			this->charCount++;
			this->free--;
		}

		// Signalisiert das Ende des Lexems
		*insertPointer++ = '\0';
		// Counter und freier Speicherplatz bez�glich NULL Byte ber�cksichtigen
		this->charCount++;
		this->free--;

		lexem = lexemCpy;

		int hashcode = Hashtable<Element>::getHashcode(lexem, lexemLength);
		Element* element = new Element(hashcode, tokenTyp, lexemPointer, lexemLength);
		hashtable->put(hashcode, element);
		
		return element;
	}
	
	 Element* Symtable::lookup(char* lexem, int lexemLength) {
		return hashtable->get(lexem, lexemLength);
	}

	void Symtable::printSymtable() {
		int size = hashtable->getSize();

		cout << "Hashtable (" << hashtable->filledPercentage() << "%, MAX: " << hashtable->getMax() << "%):" << endl;
		cout << endl;

		for (int i = 0; i < size; i++) {
			List<Element>& list = hashtable->getTable()[i];
			List<Element>::Iterator iter = list.begin();

			cout << i << ": ";

			while (iter != list.end()) {
				Element& element = **iter;
				char* lexem = element.getLexem();

				while (char letter = *lexem++) {
					cout << letter;
				}

				cout << " | " << (**iter).getHashcode() << " | " << (**iter).getLexemLength() << " -> ";

				iter++;
			}

			cout << endl;
		}

		cout << endl;

		cout << "char Arrays:" << endl;
		cout << endl;

		for (int i = 0; i <= this->currentIndex; i++) {
			char* charArray = stringTabArray[i];
			cout << i << ": ";

			for (int j = 0; j < this->stringTabLength; j++) {
				if (charArray[j] == '\0') {
					cout << "\\";
				}
				else {
					cout << charArray[j];
				}
			}

			cout << endl;
		}

		cout << endl << "Anzahl der char Arrays(" << stringTabLength << " Zeichen): ";
		cout << currentIndex + 1 << endl;
		cout << "Anazhl der char Zeichen in den Arrays inkl. NULL Bytes: " << charCount << endl;
	}

	int Symtable::getStringTabLength() {
		return this->stringTabLength;
	}

	int Symtable::getCurrentIndex() {
		return this->currentIndex;
	}

	char** Symtable::getStringTabArray() {
		return this->stringTabArray;
	}

	int Symtable::getCharCount() {
		return this->charCount;
	}
